import copy
import re

import jsonpath
import yaml

from commons.debug_talk import DebugTalk
from commons.yaml_util import write_yaml, read_all


class ExtractUtil:
    # 解析提取变量

    #     从response中提取想要的数据
    #     将提取到的数据写入到extract.yaml中
    #     将extract.yaml中的数据，在request之前，将request的${}进行一一替换
    def extract(self,res,var_name,attr_name,expr,index): # 解析提取变量
        #     uId: [json,"$.data.id"]
        #     var_name:uId        attr_name:json   expr:$.data.id(表达式)
        #     res为将前面的response传递过来
        # 深拷贝
        new_res = copy.deepcopy(res)
        # 把json方法改成json属性
        try:
            new_res.json = new_res.json()
        except Exception:
            new_res.json = {"msg":"response not json data"}
        # 通过反射获取属性的值
        data = getattr(new_res,attr_name)
        # # 从配置中获取要提取的属性名
        # attr_name = "status_code"  # 或从 YAML 配置读取
        # data = getattr(new_res, attr_name)  # 获取状态码
        #
        # # 也可以获取方法并调用
        # attr_name = "json"
        # json_method = getattr(new_res, attr_name)  # 获取 json() 方法
        # data = json_method()  # 调用方法，等价于 new_res.json()
        # 判断通过什么提取方式提取数据
        if expr.startswith("$"):
            lis = jsonpath.jsonpath(dict(data), expr)
        else:
            lis = re.findall(expr,data)
        # 取值
        if lis:
            write_yaml({var_name:lis[index]})

    # 解析使用变量
    # 从extract.yaml中提取变量的具体值，赋值给目标yaml的具体变量
    #   uId: 用户名已存在 ---->替换   目标yaml中的${uId}

    def use_extract_value(self,request_data:dict): # 解析使用变量
#       1.把字典转换为字符串
        data_str = yaml.safe_dump(request_data)
#       2.把字符串替换
#         new_request = Template(data_str).safe_substitute(read_all())
        new_request = self.hotload_replace(data_str)
#       data_str = "${name} is a ${token}"
#       print("name":"admin","token":"user")
#       打印结果: admin is a user
#       3.把字符串还原为字典
        data_dict = yaml.safe_load(new_request)
        return data_dict

    def hotload_replace(self,data_str:str):
#         定义一个正则匹配这种表达式
       # regexp = "\\$\\{(.*?)\\}"       # ${number} number = (.*?)
        regexp = "\\$\\{(.*?)\\((.*?)\\)\\}"     # ${函数名(参数)}  函数名 = (.*?) 参数 = (.*?)
#         通过正则表达式在data_str字符串中去匹配，得到所有的表达式list
        fun_list = re.findall(regexp,data_str)
        print(fun_list)
        for f in fun_list:
            if f[1] == "": # 没有参数
                new_value = getattr(DebugTalk(),f[0])
                print("value没有参数的值",new_value)
                # DebugTalk() 创建了 DebugTalk 类的一个实例
                # f[0] 是一个字符串，表示要获取的属性或方法名
                # getattr() 函数通过名称动态获取该属性或方法
            else: # 有参
                # 获取函数对象
                func = getattr(DebugTalk(), f[0])
                # 调用函数并传递参数
                new_value = func(*f[1].split(","))
                print("value有参的值",new_value)
            if isinstance(new_value,str) and new_value.isdigit():
                new_value = "'" + new_value + "'"
#             拼接旧的值
            old_value = "${" + f[0] + "(" + f[1] + ")}"
            # 旧的值指的是${read_yaml(number)},新的值指的是执行该函数最终得到的结果
            print("old_value",old_value)
            print("new_value",new_value)
#             把旧的表达式替换成函数返回的值
            data_str = data_str.replace(old_value,str(new_value))
        return data_str



